﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Tesseract;

namespace DrugCategoryCrawler
{
    public class CaptchaCracker
    {
        const string URL_VALID_CAPTCHA = "http://drugs.medlive.cn/validCaptcha.do";
        const string URL_REFERER_PREFIX = "http://drugs.medlive.cn/initCaptcha.do?orginUrl=";

        static readonly char[] WHITE_CHARS = new char[] { ' ', '\r', '\n', '\t' };
        static readonly string RUN_PATH = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        
        CookieContainer _cookieContainer = new CookieContainer();

        public string getCaptcha(string imageFile)
        {
            var image = new Bitmap(imageFile);
            var ocrtext = string.Empty;
            using (var engine = new TesseractEngine(Path.Combine(RUN_PATH, @"tessdata"), "eng", EngineMode.Default))
            {
                engine.SetVariable("tessedit_char_whitelist", "0123456789");
                for (int y = 0; y < image.Height; y++)
                {
                    for (int x = 0; x < image.Width; x++)
                    {
                        Color c = image.GetPixel(x, y);
                        float f = c.GetBrightness();
                        if (f > 0.8)
                        {
                            image.SetPixel(x, y, Color.White);
                        }
                        else
                        {
                            image.SetPixel(x, y, Color.Black);
                        }
                    }
                }
                //image.Save(Path.Combine(RUN_PATH, @"tmp.png"));
                Rect[] sections = new Rect[] { 
                    new Rect(0, 0, 15, image.Height), 
                    new Rect(16, 0, 20, image.Height), 
                    new Rect(36, 0, 20, image.Height), 
                    new Rect(56, 0, image.Width - 56, image.Height)
                };
                using (var img = PixConverter.ToPix(image))
                {
                    foreach (var section in sections)
                    {
                        using (var page = engine.Process(img, section, PageSegMode.SingleChar))
                        {
                            ocrtext += page.GetText().Trim(WHITE_CHARS);
                        }
                    }
                }
                image.Dispose();
                System.Diagnostics.Debug.WriteLine(ocrtext);
                return ocrtext;
            }
        }

        public string process(string url, string originUrl)
        {
            string file = Path.Combine(RUN_PATH, @"captcha.jpg");

            downloadFile(url, file);

            string captcha = getCaptcha(file);

            System.Console.WriteLine("captcha=" + captcha);

            string html = "";
            HttpWebRequest webReq = (HttpWebRequest)HttpWebRequest.Create(URL_VALID_CAPTCHA);
            try
            {
                webReq.CookieContainer = _cookieContainer;
                webReq.Method = "POST";
                webReq.ContentType = "application/x-www-form-urlencoded";
                webReq.Referer = URL_REFERER_PREFIX 
                    + System.Uri.EscapeDataString(originUrl);
                using (Stream inStream = webReq.GetRequestStream())
                {
                    string content =
                        "orginUrl="
                        + System.Uri.EscapeDataString(originUrl)
                        + "&captcha=" + captcha;
                    byte[] buf = System.Text.Encoding.Default.GetBytes(content);
                    inStream.Write(buf, 0, buf.Length);
                    using (WebResponse response = webReq.GetResponse())
                    {
                        using (Stream stream = response.GetResponseStream())
                        {
                            StreamReader reader = new StreamReader(stream);
                            html = reader.ReadToEnd();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex);
                throw ex;
            }
            return html;
        }

        private void downloadFile(string url, string file)
        {
            HttpWebRequest webReq = (HttpWebRequest)HttpWebRequest.Create(url);
            try
            {
                webReq.CookieContainer = _cookieContainer;
                webReq.Method = "GET";
                using (WebResponse response = webReq.GetResponse())
                {
                    FileStream fs = new FileStream(file, FileMode.OpenOrCreate);
                    byte[] buffer = new byte[1024];
                    int cnt = 0;
                    using (Stream stream = response.GetResponseStream())
                    {
                        while ((cnt = stream.Read(buffer, 0, 1024)) > 0)
                        {
                            fs.Write(buffer, 0, cnt);
                        }
                    }
                    fs.Flush();
                    fs.Close();
                }
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex);
                throw ex;
            }
        }
    }
}
